﻿using MyProject01.Agent;
using MyProject01.Controller;
using MyProject01.Controller.Jobs;
using MyProject01.DAO;
using MyProject01.RProjects;
using MyProject01.Util;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyProject01.TestCases
{
    interface IFittnessCalculator
    {
        string Name { get; }
        string Description { get; }
        DataBlock[] SignalData { set; }
        double CalcFittness(TraderResult result);
    }

    class TraderCommand
    {
        public double Price;
        public MarketActions Action;

        public override string ToString()
        {
            return String.Format("P:{0}, A:{1}", Price, Action.ToString());
        }
    }

    class TraderCommandArray
    {
        private TraderCommand[] _cmdArr;
        private int _length;

        public int Length
        {
            set
            {
                _length = value;
                if (_cmdArr.Length < _length)
                {
                    _cmdArr = new TraderCommand[_length];
                    for (int i = 0; i < _cmdArr.Length; i++)
                    {
                        _cmdArr[i] = new TraderCommand();
                    }
                }
            }
            get { return _length; }
        }

        public TraderCommandArray(int length)
        {
            _cmdArr = new TraderCommand[length];
            for (int i = 0; i < _cmdArr.Length; i++)
            {
                _cmdArr[i] = new TraderCommand();
            }

            _length = length;
        }

        public TraderCommand this[int index]
        {
            get { return _cmdArr[index]; }
        }
    }




    class TraderResult
    {
        public int TraderLogLength;
        public DealLog[] LogArr;
        public List<OrderLog> OrderList;
    }

    class NormalOrderAgent
    {
        public double InitMoney = 10000;

        private Order _order;
        private DealLog[] _logArr;

        public double BuyOffset;
        public double SellOffset;


        public NormalOrderAgent(int maxCmdLength)
        {
            _logArr = new DealLog[maxCmdLength];
        }

        public TraderResult Run(TraderCommandArray cmdList)
        {
            List<OrderLog> orderList = new List<OrderLog>(cmdList.Length);
            TraderCommand cmd;

            _order = new Order(InitMoney) { BuyOffset = BuyOffset, SellOffset = SellOffset };

            for (int i = 0; i < cmdList.Length; i++)
            {
                OrderLog order = null;

                cmd = cmdList[i];

                _logArr[i].CurrentMoney = _order.GetCurrentMoney(cmd.Price);

                order = TakeAction(cmd.Action, cmd.Price);
                _logArr[i].Action = cmd.Action;
                _logArr[i].Rate = cmd.Price;

                if (order != null)
                    orderList.Add(order);
            }

            TraderResult result = new TraderResult()
            {
                TraderLogLength = cmdList.Length,
                LogArr = _logArr,
                OrderList = orderList
            };
            return result;
        }

        private OrderLog TakeAction(MarketActions action, double currentPrice)
        {
            OrderLog order = null;
            switch (action)
            {
                case MarketActions.Buy:
                    order = _order.StartOrder(Order.OrderType.BuyOrder, currentPrice);
                    break;
                case MarketActions.Sell:
                    order = _order.StartOrder(Order.OrderType.SellOrder, currentPrice);
                    break;
                case MarketActions.Close:
                    order = _order.CloseOrder(currentPrice);
                    break;
                case MarketActions.Nothing:
                    break;
                default:
                    break;
            }
            return order;
        }

    }
    public class ObjectPool<T>
    {
        private ConcurrentBag<T> _objects;
        private Func<T> _objectGenerator;

        public ObjectPool(Func<T> objectGenerator)
        {
            if (objectGenerator == null) throw new ArgumentNullException("objectGenerator");
            _objects = new ConcurrentBag<T>();
            _objectGenerator = objectGenerator;
        }

        public T GetObject()
        {
            T item;
            if (_objects.TryTake(out item)) return item;
            return _objectGenerator();
        }

        public void PutObject(T item)
        {
            _objects.Add(item);
        }
    }
    //=======================================================================
    class FreeTraderFittnessCalculator : IFittnessCalculator
    {
        public string Description
        {
            get
            {
                return "FreeTraderFittnessCalculator";
            }
        }

        public string Name
        {
            get
            {
                return "FreeTrader"; ;
            }
        }

        public DataBlock[] SignalData
        {
            set
            {
                return;
            }
        }

        public double CalcFittness(TraderResult result)
        {
            return result.LogArr[result.TraderLogLength - 1].CurrentMoney;
        }
    }
    class FreeTrader2FittnessCalculator : IFittnessCalculator
    {
        public string Description
        {
            get
            {
                return "FreeTraderFittnessCalculator";
            }
        }

        public string Name
        {
            get
            {
                return "FreeTrader"; ;
            }
        }

        public DataBlock[] SignalData
        {
            set
            {
                return;
            }
        }

        public double CalcFittness(TraderResult result)
        {
            return result.LogArr[result.TraderLogLength - 1].CurrentMoney;
        }
    }
    class FreeTraderPowerFittnessCalculator : IFittnessCalculator
    {
        private const double powNum = 20;

        public string Description
        {
            get
            {
                return "FreeTraderPowerFitCalc";
            }
        }

        public string Name
        {
            get
            {
                return "FreeTraderPower"; ;
            }
        }

        public DataBlock[] SignalData
        {
            set
            {
                return;
            }
        }

        public double CalcFittness(TraderResult result)
        {
            double sum = 0;
            for (int i = 0; i < result.TraderLogLength - 1; i++)
            {


                double ern = (result.LogArr[i + 1].CurrentMoney - result.LogArr[i].CurrentMoney) / (double)result.LogArr[i].CurrentMoney;


                ern = Math.Pow(ern + 1, powNum);

                sum += ern;

            }

            sum += 100000;

            if (sum < 0)
                sum = 0;
            return sum;
        }
    }




    class SigErrorFittnessCalculator : IFittnessCalculator
    {
        DataBlock[] _signalData;

        public string Description
        {
            get
            {
                return "SigErrorFittnessCalculator";
            }
        }

        public string Name
        {
            get
            {
                return "SigError";
            }
        }

        public DataBlock[] SignalData
        {
            set
            {
                _signalData = value;
            }
        }

        public double CalcFittness(TraderResult result)
        {
            double error = CalculateError(result, _signalData);
            return 1 - error;
        }
        private double CalculateError(TraderResult result, DataBlock[] resultData)
        {
            double sum = 0;
            double previorValue = 0;
            double value;
            int sameCount = 0;
            for (int i = 0; i < result.TraderLogLength; i++)
            {
                DealLog log = result.LogArr[i];
                if (log.Action == MarketActions.Buy)
                    value = 1;
                else if (log.Action == MarketActions.Sell)
                    value = -1;
                else
                    value = previorValue;
                if (value != resultData[i][0])
                    sameCount++;
            }
            sum = (double)sameCount / result.TraderLogLength;

            return sum;
        }
    }

    class SigError2FittnessCalculator : IFittnessCalculator
    {
        DataBlock[] _signalData;

        public string Description
        {
            get
            {
                return "SigError2FittnessCalculator";
            }
        }

        public string Name
        {
            get
            {
                return "SigError2";
            }
        }

        public DataBlock[] SignalData
        {
            set
            {
                _signalData = value;
            }
        }

        public double CalcFittness(TraderResult result)
        {
            return CalculateError(result, _signalData);
        }
        private double CalculateError(TraderResult result, DataBlock[] resultData)
        {
            double sum = 0;
            double previorValue = 0;
            double value;
            for (int i = 0; i < result.TraderLogLength - 1; i++)
            {
                DealLog log = result.LogArr[i];
                double score;
                if (log.Action == MarketActions.Buy)
                    value = 1;
                else if (log.Action == MarketActions.Sell)
                    value = -1;
                else
                    value = previorValue;
                if (value == resultData[i][0])
                    score = 1;
                else
                    score = 0;

                score *= result.LogArr[i + 1].CurrentMoney - result.LogArr[i].CurrentMoney;

                sum += score;

            }

            return sum;
        }
    }
    class SigError3FittnessCalculator : IFittnessCalculator
    {
        DataBlock[] _signalData;

        public string Description
        {
            get
            {
                return "SigError3FitCalcs";
            }
        }

        public string Name
        {
            get
            {
                return "SigError3";
            }
        }

        public DataBlock[] SignalData
        {
            set
            {
                _signalData = value;
            }
        }

        public double CalcFittness(TraderResult result)
        {
            return CalculateError(result, _signalData);
        }
        private double CalculateError(TraderResult result, DataBlock[] resultData)
        {
            double sum = 0;
            double previorValue = 0;
            double value;
            for (int i = 0; i < result.TraderLogLength - 1; i++)
            {
                DealLog log = result.LogArr[i];
                double score;
                if (log.Action == MarketActions.Buy)
                    value = 1;
                else if (log.Action == MarketActions.Sell)
                    value = -1;
                else
                    value = previorValue;
                if (value == resultData[i][0])
                    score = 1;
                else
                    score = -2;

                score *= Math.Abs(result.LogArr[i + 1].CurrentMoney - result.LogArr[i].CurrentMoney);

                sum += score;

            }
            sum += result.TraderLogLength * 10;
            if (sum < 0)
                sum = 0;

            return sum;
        }
    }

    class SigErrorPowerFittnessCalculator : IFittnessCalculator
    {
        DataBlock[] _signalData;
        private const double powNum = 20;

        public string Description
        {
            get
            {
                return "SigErrorPowerFitCalc";
            }
        }

        public string Name
        {
            get
            {
                return "SigErrorPower";
            }
        }

        public DataBlock[] SignalData
        {
            set
            {
                _signalData = value;
            }
        }

        public double CalcFittness(TraderResult result)
        {
            return CalculateError(result, _signalData);
        }
        private double CalculateError(TraderResult result, DataBlock[] resultData)
        {
            double sum = 0;
            double previorValue = 0;
            double value;
            for (int i = 0; i < result.TraderLogLength - 1; i++)
            {
                DealLog log = result.LogArr[i];
                double score;
                if (log.Action == MarketActions.Buy)
                    value = 1;
                else if (log.Action == MarketActions.Sell)
                    value = -1;
                else
                    value = previorValue;
                if (value == resultData[i][0])
                    score = 1;
                else
                    score = 0;

                score *= Math.Pow(result.LogArr[i + 1].CurrentMoney - result.LogArr[i].CurrentMoney + 1, powNum);

                sum += score;

            }

            return sum;
        }
    }
    class SigErrorPower2FittnessCalculator : IFittnessCalculator
    {
        DataBlock[] _signalData;
        private const double powNum = 20;

        public string Description
        {
            get
            {
                return "SigErrorPower2FitCalc";
            }
        }

        public string Name
        {
            get
            {
                return "SigErrorPower2";
            }
        }

        public DataBlock[] SignalData
        {
            set
            {
                _signalData = value;
            }
        }

        public double CalcFittness(TraderResult result)
        {
            return CalculateError(result, _signalData);
        }
        private double CalculateError(TraderResult result, DataBlock[] resultData)
        {
            double sum = 0;
            double previorValue = 0;
            double value;
            for (int i = 0; i < result.TraderLogLength - 1; i++)
            {
                DealLog log = result.LogArr[i];
                double score;
                if (log.Action == MarketActions.Buy)
                    value = 1;
                else if (log.Action == MarketActions.Sell)
                    value = -1;
                else
                    value = previorValue;
                if (value == resultData[i][0])
                    score = 1;
                else
                    score = -1;
                double ern = result.LogArr[i + 1].CurrentMoney - result.LogArr[i].CurrentMoney;


                score *= Math.Pow(Math.Abs(ern) + 1, powNum);

                sum += score;

            }

            sum += 10000;
            if (sum < 0)
                sum = 0;

            return sum;
        }
    }
    // ========================================
    class TrainingResultSave
    {
        private RateMarketTestDAO _testCaseDAO;

        public TrainingResultSave(string testName, string testDesc)
        {
            _testCaseDAO = RateMarketTestDAO.GetDAO<RateMarketTestDAO>(testName, true);
            _testCaseDAO.TestDescription = testDesc;
            _testCaseDAO.Time = DateTime.Now;


        }

        public void SaveResult(int epoch, TraderResult trainResult, TraderResult testResult)
        {
            _testCaseDAO.TotalDataCount = trainResult.TraderLogLength + testResult.TraderLogLength;
            _testCaseDAO.TestDataStartIndex = trainResult.TraderLogLength;

            RateMarketTestEpisodeDAO epsodeLog = (RateMarketTestEpisodeDAO)_testCaseDAO.CreateEpisode();
            epsodeLog.TrainedDataEarnRate = (trainResult.LogArr[trainResult.TraderLogLength - 1].CurrentMoney / trainResult.LogArr[0].CurrentMoney) * 100;
            epsodeLog.UnTrainedDataEarnRate = (testResult.LogArr[testResult.TraderLogLength - 1].CurrentMoney / testResult.LogArr[0].CurrentMoney) * 100;
            epsodeLog.TrainedDealCount = trainResult.OrderList.Count;
            epsodeLog.UntrainedDealCount = testResult.OrderList.Count;
            // epsodeLog.HidenNodeCount = network.Links.Length;
            epsodeLog.Step = epoch;
            epsodeLog.ControllerName = ""; // TODO
            epsodeLog.Time = DateTime.Now;
            epsodeLog.Save();

            DealLogList logList = new DealLogList();
            logList.Add(trainResult.LogArr, trainResult.TraderLogLength);
            logList.Add(testResult.LogArr, testResult.TraderLogLength);
            epsodeLog.SaveDealLogs(logList);

            _testCaseDAO.LastTrainedDataEarnRate = epsodeLog.TrainedDataEarnRate;
            _testCaseDAO.LastTestDataEarnRate = epsodeLog.UnTrainedDataEarnRate;
            _testCaseDAO.LastUpdateTime = epsodeLog.Time;
            _testCaseDAO.Step = epoch;
            _testCaseDAO.Save();
        }


    }


    class ZagZigTrainerEventHandler : ITrainerEventHandler
    {
        public DataBlock[] TrainData;
        public RateSet[] TrainRate;
        public DataBlock[] TrainResult;
        public DataBlock[] TestData;
        public RateSet[] TestRate;
        public DataBlock[] TestResult;


        protected ObjectPool<TraderCommandArray> _traderCmdPool;
        protected ObjectPool<NormalOrderAgent> _agentPool;
        protected double _dealOffset = 0.01;
        private double _lastFittness;

        private TrainingResultSave _resutlSaver;

        virtual public string Name { get { return ""; } }
        virtual public string Description { get { return ""; } }

        public void Init(TrainingResultSave resutlSaver, int cap)
        {
            _traderCmdPool = new ObjectPool<TraderCommandArray>(() => new TraderCommandArray(cap));
            _agentPool = new ObjectPool<NormalOrderAgent>(() => new NormalOrderAgent(cap));
            _lastFittness = -1;

            _resutlSaver = resutlSaver;
        }


        public void Start()
        {
            // throw new NotImplementedException();
        }

        public void Update(TrainingResult result)
        {

            TraderCommandArray cmdArr;

            if (_lastFittness == result.Fitness)
                return;
            _lastFittness = result.Fitness;

            NormalOrderAgent bestTrainAgent = _agentPool.GetObject();
            bestTrainAgent.BuyOffset = bestTrainAgent.SellOffset = _dealOffset;
            cmdArr = CreateBestCmd(TrainResult, TrainRate);
            TraderResult bestTrainResult = bestTrainAgent.Run(cmdArr);
            double bestTrainMoneyRemain = bestTrainResult.LogArr[bestTrainResult.TraderLogLength - 1].CurrentMoney;
            double bestTrainSumError = CalculateError(bestTrainResult, TrainResult);
            _traderCmdPool.PutObject(cmdArr);

            NormalOrderAgent trainAgent = _agentPool.GetObject();
            trainAgent.BuyOffset = trainAgent.SellOffset = _dealOffset;
            cmdArr = CreateCmd(result.BestNetwork, TrainData, TrainRate);
            TraderResult trainResult = trainAgent.Run(cmdArr);
            double trainMoneyRemain = trainResult.LogArr[trainResult.TraderLogLength - 1].CurrentMoney;
            double trainSumError = CalculateError(trainResult, TrainResult);
            _traderCmdPool.PutObject(cmdArr);

            NormalOrderAgent testAgent = _agentPool.GetObject();
            testAgent.BuyOffset = testAgent.SellOffset = _dealOffset;
            cmdArr = CreateCmd(result.BestNetwork, TestData, TestRate);
            TraderResult testResult = testAgent.Run(cmdArr);
            double testMoneyRemain = testResult.LogArr[testResult.TraderLogLength - 1].CurrentMoney;
            double testSumError = CalculateError(testResult, TestResult);
            _traderCmdPool.PutObject(cmdArr);


            _resutlSaver.SaveResult(result.Epoch, trainResult, testResult);

            LogFile.WriteLine(String.Format("Training {0,5}: {1:#####} / {2:0.0000}, {3:#####} / {4:0.0000}",
                result.Epoch,
                trainMoneyRemain, trainSumError,
                testMoneyRemain, testSumError));

            _agentPool.PutObject(bestTrainAgent);
            _agentPool.PutObject(trainAgent);
            _agentPool.PutObject(testAgent);
        }

        protected TraderCommandArray CreateCmd(INetObject net, DataBlock[] data, RateSet[] rate)
        {
            TraderCommandArray cmdArr = _traderCmdPool.GetObject();
            cmdArr.Length = data.Length;

            DataBlock[] resArr = net.Calculate(data);

            for (int i = 0; i < resArr.Length; i++)
            {
                MarketActions act;
                DataBlock result = resArr[i];

                // System.Console.WriteLine(String.Format("{0:0.0000}", result[0]));

                if (result[0] >= 0.5)
                    act = MarketActions.Buy;
                else
                    act = MarketActions.Sell;
                cmdArr[i].Action = act;
                cmdArr[i].Price = rate[i].Close;
            }

            return cmdArr;
        }

        protected TraderCommandArray CreateBestCmd(DataBlock[] resultArr, RateSet[] rate)
        {
            TraderCommandArray cmdArr = _traderCmdPool.GetObject();
            cmdArr.Length = resultArr.Length;
            for (int i = 0; i < resultArr.Length; i++)
            {
                MarketActions act;
                DataBlock result = resultArr[i];

                // System.Console.WriteLine(String.Format("{0:0.0000}", result[0]));

                if (result[0] == 1)
                    act = MarketActions.Buy;
                else
                    act = MarketActions.Sell;
                cmdArr[i].Action = act;
                cmdArr[i].Price = rate[i].Close;
            }

            return cmdArr;
        }
        private double CalculateError(TraderResult result, DataBlock[] resultData)
        {
            double sum = 0;
            double previorValue = 0;
            double value;
            int sameCount = 0;
            for (int i = 0; i < result.TraderLogLength; i++)
            {
                DealLog log = result.LogArr[i];
                if (log.Action == MarketActions.Buy)
                    value = 1;
                else if (log.Action == MarketActions.Sell)
                    value = -1;
                else
                    value = previorValue;
                if (value != resultData[i][0])
                    sameCount++;
            }
            sum = (double)sameCount / result.TraderLogLength;

            return sum;
        }



    }
    class ZagZigTrainerWithNeatEventHandler : ZagZigTrainerEventHandler, INeatEvalutor
    {
        private IFittnessCalculator _fitCalc;

        public override string Name
        {
            get
            {
                return _fitCalc.Name;
            }
        }

        public override string Description
        {
            get
            {
                return _fitCalc.Description;
            }
        }

        public ZagZigTrainerWithNeatEventHandler(IFittnessCalculator fitCalc)
        {
            _fitCalc = fitCalc;
        }

        public double CalcFittness(INetObject net)
        {
            NormalOrderAgent agent = _agentPool.GetObject();
            agent.BuyOffset = agent.SellOffset = _dealOffset;

            TraderCommandArray cmdArr = CreateCmd(net, TrainData, TrainRate);
            TraderResult result = agent.Run(cmdArr);
            _fitCalc.SignalData = this.TrainResult;
            double error = _fitCalc.CalcFittness(result);

            _traderCmdPool.PutObject(cmdArr);
            _agentPool.PutObject(agent);

            return error;
        }

    }

    class ZagZigTrainerWithDarchEventHandler : ZagZigTrainerEventHandler, IDarchTrainerDataObject
    {
        public DataBlock[] InData
        {
            get
            {
                return this.TrainData;
            }
        }

        public DataBlock[] SigData
        {
            get
            {
                return this.TrainResult;
            }
        }
    }

    class ZigZigUtility
    {
        static public DataBlock[] ConvertToInData(RateSet[] rate, int startPosition, int length)
        {
            return RUtility.ConvertInData(rate, startPosition, length);
        }
        static public DataBlock[] ConvertOutDat(RateSet[] rate, int startPosition, int length)
        {
            return RUtility.ConvertZigZag(rate, startPosition, length);
        }
    }

    class ZagZigTestCase : ITestCase
    {
        private BasicTestDataLoader _loader;
        private ITrainer _trainer;
        private ZagZigTrainerEventHandler _handler;

        private int _testCount = 1000;
        private int _startPosition = 100;

        public string Name
        {
            get { return "ZagZigTestCase" + "-" + _loader.Name + "-" + _trainer.Name + "-" + _handler.Name; }
        }

        public string Description
        {
            get { return "ZagZig Test: " + "-" + _loader.Description + "-" + _trainer.Description + "-" + _handler.Description; }
        }

        public BasicTestDataLoader Loader { set { _loader = value; } }
        public ITrainer Trainer { set { _trainer = value; } }
        public int StartPosition { set { _startPosition = value; } }
        public ZagZigTrainerEventHandler Handle { set { _handler = value; } }
        public void Run()
        {
            // Config Server IP
            DataBaseAddress.SetIP(CommonConfig.ServerIP);

            _loader.Load();
#if true
            int totalLength = _loader.Count - _startPosition;
#else
            int totalLength = 2000;
#endif

            DataBlock[] inData = ZigZigUtility.ConvertToInData(_loader.ToArray(), _startPosition, totalLength);
            DataBlock[] outData = ZigZigUtility.ConvertOutDat(_loader.ToArray(), _startPosition, totalLength);

            DataRangeCalculator range = new DataRangeCalculator();
            range.SetSize(_startPosition, totalLength, _testCount);

            TrainingResultSave resultSaver = new TrainingResultSave(Name + " | " + DateTime.Now, Description);

            _handler.Init(resultSaver, inData.Length);

            ArraySliceCreate<DataBlock> slice = new ArraySliceCreate<DataBlock>();
            slice.Target = inData;
            _handler.TrainData = slice.Get(range.TrainStartPos - _startPosition, range.TrainLength);
            _handler.TestData = slice.Get(range.TestStartPos - _startPosition, range.TestLength);

            slice.Target = outData;
            _handler.TrainResult = slice.Get(range.TrainStartPos - _startPosition, range.TrainLength);
            _handler.TestResult = slice.Get(range.TestStartPos - _startPosition, range.TestLength);

            ArraySliceCreate<RateSet> slice3 = new ArraySliceCreate<RateSet>();
            slice3.Target = _loader.ToArray();
            _handler.TrainRate = slice3.Get(range.TrainStartPos, range.TrainLength);
            _handler.TestRate = slice3.Get(range.TestStartPos, range.TestLength);

            _trainer.SetEventHandler(_handler);
            _trainer.InputDataLength = inData[0].Length;
            _trainer.OutputDataLength = 1;
            _trainer.Start();
        }

        public void Stop()
        {
            _trainer.Stop();
        }
    }

    class ArraySliceCreate<T>
    {
        public T[] Target;
        public T[] Get(int start, int length)
        {
            T[] arr = new T[length];
            for(int i=0;i< length; i++)
            {
                arr[i] = Target[start + i];
            }

            return arr;
        }
    }

    class DataRangeCalculator
    {
        private int _trainStartPos;
        private int _trainEndPos;
        private int _trainLength;

        private int _testStartPos;
        private int _testEndPos;
        private int _testLength;

        public int TrainStartPos { get { return _trainStartPos; } }
        public int TrainEndPos { get { return _trainEndPos; } }
        public int TrainLength { get { return _trainLength; }   }
        
        public int TestStartPos { get { return _testStartPos; } }
        public int TestEndPos { get { return _testEndPos; } }
        public int TestLength { get { return _testLength; } }

        public void SetSize(int startPos, int length, double testRadio)
        {
            _trainLength = (int)(length * testRadio);
            _trainStartPos = startPos;
            _trainEndPos = startPos + _trainLength - 1;

            _testStartPos = _trainStartPos + _trainLength;
            _testLength = length - _trainLength;
            _testEndPos = _testStartPos + _testLength - 1;
        }
        public void SetSize(int startPos, int length, int testLength)
        {
            _trainLength = length - testLength;
            _trainStartPos = startPos;
            _trainEndPos = startPos + _trainLength - 1;

            _testStartPos = _trainStartPos + _trainLength;
            _testLength = length - _trainLength;
            _testEndPos = _testStartPos + _testLength - 1;
        }
    }

}
